﻿/*
 * copyright (c) 2009 hvbird
 *
 * This file is part of tdlib.
 *
 * tdlib is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * tdlib is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 */

using System;
using System.IO;
using System.Security;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
using System.Text;

namespace TDLib.Security
{
    /// <summary>
    /// CRC 效验
    /// 快速检测算法
    /// </summary>
    public class CRC32
    {
        private ulong crcNumber = 0xEDB88320;

        /// <summary>
        /// 获取或设置用来生成Crc校验表的数字
        /// </summary>
        public ulong CrcNumber
        {
            get 
            {
                return crcNumber;
            }
            set 
            {
                crcNumber = value;
            }
        }

        /// <summary>
        /// 初始化实例
        /// </summary>
        public CRC32() { }

        /// <summary>
        /// 初始化实例
        /// </summary>
        /// <param name="crcNumber">构造Crc校验表的数字</param>
        public CRC32(ulong crcNumber)
        {
            this.crcNumber = crcNumber;
        }

        /// <summary>
        /// 初始化效验表
        /// </summary>
        private ulong[] GetCRC32()
        {
            ulong dwCrc;
            ulong[] crc32Table = new ulong[256];
            int i, j;
            for (i = 0; i < 256; i++)
            {
                dwCrc = (ulong)i;
                for (j = 8; j > 0; j--)
                {
                    if ((dwCrc & 1) == 1)
                        dwCrc = (dwCrc >> 1) ^ crcNumber;
                    else
                        dwCrc >>= 1;
                }
                crc32Table[i] = dwCrc;
            }
            return crc32Table;
        }

        /// <summary>
        /// 字节数组效验
        /// </summary>
        /// <param name="buffer">ref 字节数组</param>
        /// <returns></returns>
        public ulong ByteCRC(ref byte[] buffer)
        {
            ulong ulCRC = 0xffffffff;
            ulong len;
            len = (ulong)buffer.Length;
            for (ulong buffptr = 0; buffptr < len; buffptr++)
            {
                ulong tabPtr = ulCRC & 0xFF;
                tabPtr = tabPtr ^ buffer[buffptr];
                ulCRC = ulCRC >> 8;
                ulCRC = ulCRC ^ GetCRC32()[tabPtr];
            }
            return ulCRC ^ 0xffffffff;
        }

        /// <summary>
        /// 字符串效验
        /// </summary>
        /// <param name="inputString">字符串</param>
        /// <returns></returns>
        public ulong StringCRC(string inputString)
        {
            return StringCRC(inputString);
        }

        /// <summary>
        /// 字符串效验
        /// </summary>
        /// <param name="inputString">字符串</param>
        /// <param name="encoding">字符编码</param>
        /// <returns></returns>
        public ulong StringCRC(string inputString,System.Text.Encoding encoding)
        {
            byte[] buffer = encoding.GetBytes(inputString);
            return ByteCRC(ref buffer);
        }

        /// <summary>
        /// 文件效验
        /// </summary>
        /// <param name="inputFilename">输入文件</param>
        /// <returns></returns>
        public ulong FileCRC(string inputFilename)
        {
            using (FileStream inFile = new System.IO.FileStream(inputFilename, System.IO.FileMode.Open, System.IO.FileAccess.Read))
            {
                byte[] bInput = new byte[inFile.Length];
                inFile.Read(bInput, 0, bInput.Length);
                return ByteCRC(ref bInput);
            }
        }

    }
}
